package com.by.toolkit.utils;

import cn.hutool.core.date.StopWatch;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
 * excel写数据工具类
 *
 * @author YanBingHao
 * @since 2024/1/24
 */
@Slf4j
public final class ExcelWriteDataUtil {

    /**
     * 将数据写入byte数组
     * 不生成临时文件
     *
     * @param datas
     * @param isXlsx
     * @return
     */
    public static byte[] write2Byte(List<?> datas, Map<String, String> headerAlias, boolean onlyAlias, boolean isXlsx, List<Consumer<ExcelWriter>> cunsumers) {
      return IoUtil.readBytes(write2InputStream(datas, headerAlias, onlyAlias, isXlsx, cunsumers));
    }

    /**
     * 将数据写入输入流
     * 不生成临时文件
     *
     * @param datas
     * @param isXlsx
     * @return
     */
    public static InputStream write2InputStream(List<?> datas, Map<String, String> headerAlias, boolean onlyAlias, boolean isXlsx, List<Consumer<ExcelWriter>> cunsumers) {

        StopWatch stopWatch = new StopWatch();
        stopWatch.start("getWriter");
        ExcelWriter writer;
        if(isXlsx){
            writer  = ExcelUtil.getBigWriter();
        }else {
            writer = ExcelUtil.getWriter(isXlsx);
        }
        stopWatch.stop();
        writer.setHeaderAlias(headerAlias);
        writer.setOnlyAlias(onlyAlias);
        stopWatch.start("writeData");
        for (List<?> subDataList : Lists.partition(datas, 500)) {
            writer.write(subDataList, true);
        }
        stopWatch.stop();
        stopWatch.start("consumers");
        if (CollectionUtils.isNotEmpty(cunsumers)) {
            cunsumers.forEach(c -> {
                try {
                    c.accept(writer);
                } catch (Exception e) {
                    log.warn("[ExcelWriteDataUtil][write2InputStream] hasException:[{}] ", ExceptionUtil.getStackTrace(e));
                }
            });
        }
        stopWatch.stop();
        stopWatch.start("outputStream");
//        writer.autoSizeColumnAll();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        writer.flush(outputStream, true);
        stopWatch.stop();
        stopWatch.start("writerClose");
        writer.close();
        stopWatch.stop();
        stopWatch.start("IoUtilToStream");
        ByteArrayInputStream stream = IoUtil.toStream(outputStream);
        stopWatch.stop();
        for (StopWatch.TaskInfo taskInfo : stopWatch.getTaskInfo()) {
            log.info("[ExcelWriteDataUtil][write2InputStream] taskInfoName:[{}] executeTime:[{}]",taskInfo.getTaskName(),taskInfo.getTimeMillis());
        }
        return stream;
    }

//    public static InputStream write2InputStreamWithEasyExcel(List<?> datas,
//                                                             Map<String, String> headerAlias,
//                                                             boolean isXlsx) {
//
//        StopWatch stopWatch = new StopWatch();
//        stopWatch.start("prepare");
//
//        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
//
//        // 构造表头
//        List<List<String>> headList = new ArrayList<>();
//        for (Map.Entry<String, String> entry : headerAlias.entrySet()) {
//            headList.add(Collections.singletonList(entry.getValue()));
//        }
//
//        // 构造字段顺序
//        List<String> fieldOrder = new ArrayList<>(headerAlias.keySet());
//
//        // 构建 writer
//        ExcelWriterBuilder writerBuilder = EasyExcel.write(outputStream)
//                .excelType(isXlsx ? ExcelTypeEnum.XLSX : ExcelTypeEnum.XLS)
//                .head(headList);
//
//        com.alibaba.excel.ExcelWriter excelWriter = writerBuilder.build();
//        WriteSheet writeSheet = EasyExcel.writerSheet("sheet1").build();
//
//        stopWatch.stop();
//        stopWatch.start("write");
//
//        // 写数据（对象类型为 Map，需手动按列顺序处理）
//        List<List<?>> rowData = datas.stream()
//                .map(data -> {
//                    if (data instanceof Map) {
//                        Map<?, ?> map = (Map<?, ?>) data;
//                        return fieldOrder.stream().map(map::get).collect(Collectors.toList());
//                    } else {
//                        // Bean -> Map
//                        Map<String, Object> map = BeanUtil.beanToMap(data);
//                        return fieldOrder.stream().map(map::get).collect(Collectors.toList());
//                    }
//                })
//                .collect(Collectors.toList());
//        for (List<List<?>> lists : Lists.partition(rowData, 500)) {
//            excelWriter.write(lists, writeSheet);
//        }
//        stopWatch.stop();
//        stopWatch.start("finish");
//        excelWriter.finish();
//        stopWatch.stop();
//        ByteArrayInputStream inputStream = IoUtil.toStream(outputStream);
//        for (StopWatch.TaskInfo taskInfo : stopWatch.getTaskInfo()) {
//            log.info("[ExcelWriteDataUtil][EasyExcel] task: [{}] - time: [{}]ms", taskInfo.getTaskName(), taskInfo.getTimeMillis());
//        }
//        return inputStream;
//    }


    public static void writePic(Sheet sheet, int x, int y, byte[] picData) {
        Drawing<?> drawingPatriarch = sheet.createDrawingPatriarch();
        ClientAnchor anchor = drawingPatriarch.createAnchor(0, 0, 0, 0, x, y, x + 1, y + 1);
        anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);

        drawingPatriarch.createPicture(anchor, sheet.getWorkbook().addPicture(picData, Workbook.PICTURE_TYPE_JPEG));
    }

    public static void mergeCell(ExcelWriter writer, Merge merge) {
        writer.merge(merge.getFirstRow(), merge.getLastRow(), merge.getFirstColumn(), merge.getLastColumn(), merge.getContent(), merge.isSetHeaderStyle());
    }

    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Merge {

        private int firstRow;

        private int lastRow;

        private int firstColumn;

        private int lastColumn;

        private Object content;

        private boolean isSetHeaderStyle;

    }

    public static CellStyle successStyle(Workbook workbook){
        CellStyle style = workbook.createCellStyle();
        style.setFillBackgroundColor(HSSFColor.HSSFColorPredefined.GREEN.getColor());
        return style;
    }

    public static CellStyle failStyle(Workbook workbook){
        CellStyle style = workbook.createCellStyle();
        style.setFillBackgroundColor(HSSFColor.HSSFColorPredefined.RED.getColor());
        return style;
    }

}
